package main

import (
	"fmt"
	"reflect"
)

// 指针
func main() {
	println("##### test1 ####")
	test1()
	println("##### test2 ####")
	test2()
	println("##### test3 ####")
	test3()
}

/*
如果用“var x int”声明语句声明一个x变量,那么
1. p := &x   表示p是一个指向该x变量的指针，也就是p是x变量的内存地址
2. n := *p   表示p是获得x变量指针的值
*/
func test1() {
	x := 1
	fmt.Println(reflect.TypeOf(x)) // int

	p := &x                        // p, of type *int, points to x
	fmt.Println(reflect.TypeOf(p)) // *int
	fmt.Println(p)                 // 0xc00001c0a8
	fmt.Println(*p)                // 1

	// 通过指针修改内存地址中保存的数据，这样所有指向该地址的变量的值都发生变化
	*p = 2         // equivalent to x = 2
	fmt.Println(p) // 0xc00001c0a8
	fmt.Println(x) // 2。 指针指向的值变修改了，所以x也被修改了
}

// 任何类型的指针的零值都是nil。如果p指向某个有效变量，那么p != nil测试为真。
// 指针之间也是可以进行相等测试的，只有当它们指向同一个变量或全部是nil时才相等。
func test2() {
	var a, b int
	fmt.Println(a, b)
	fmt.Println("同一个变量的指针", &a == &a)  //true
	fmt.Println("不同变量的指针", &a == &b)   //false
	fmt.Println("指针与nil比较", &a == nil) // false
}

// 返回函数中局部变量的地址也是安全的
func test3() {
	p := fun3_1()
	fmt.Println(reflect.TypeOf(p)) // *int
	fmt.Println(p)                 // 0xc00001c110
	fmt.Println(*p)                // 1

	// 每次调用f函数都将返回不同的结果
	fmt.Println(fun3_1() == fun3_1()) //false

	// 传入指针，方法对指针的值进行修改。
	a := 1
	fmt.Println("a变量的指针和值,", &a, "数值：", a)
	for i := 0; i < 2; i++ {
		a = fun3_2(&a)
		fmt.Println("a变量的指针和值, i=", i, &a, "数值：", a)
	}

}

func fun3_1() *int {
	res := 1
	return &res
}

func fun3_2(p *int) int {
	*p++ // 非常重要：只是增加p指向的变量的值，并不改变p指针！！！
	return *p
}
